﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Data;
using System.Data.Common;
using SEAM.Data;

namespace SEAM.Test.Data
{
    /// <summary>
    /// Summary description for DataAccess_Northwind
    /// </summary>
    [TestClass]
    public class DataAccess_Northwind_Customer
    {
        public DataAccess_Northwind_Customer()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext) 
        {
            Assert.IsTrue(DataAccess.Initialized == true);
        }

        [TestMethod]
        public void ValidateSimpleReturnTypes()
        {
            int total = DataAccess.ExecuteQuery("SELECT 10").First<int>();
            Assert.IsTrue(total == 10, "Could not cast to int");

            int? total2 = DataAccess.ExecuteQuery("SELECT null").First<int?>();
            Assert.IsNull(total2, "Could not set null for int?");

            int? total3 = DataAccess.ExecuteQuery("SELECT 10").First<int?>();
            Assert.IsTrue(total3.Value == 10, "Could not set value for int?");


            DateTime curDate = DataAccess.ExecuteQuery("SELECT CAST('12/31/2009' AS DateTime)").First<DateTime>();
            Assert.IsTrue(curDate == DateTime.Parse("12/31/2009"), "Could not cast to DateTime");

            DateTime? curDate2 = DataAccess.ExecuteQuery("SELECT null").First<DateTime?>();
            Assert.IsNull(curDate2, "Could not set null for DateTime?");

            DateTime? curDate3 = DataAccess.ExecuteQuery("SELECT CAST('12/31/2009' AS DateTime)").First<DateTime?>();
            Assert.IsTrue(curDate3.Value == DateTime.Parse("12/31/2009"), "Could not set value for DateTime?");
        }

        [TestMethod]
        public void ValidateCustomerDataTable()
        {
            DataTable dtCustomers = DataAccess.ExecuteQuery("SELECT * FROM Customers");

            Assert.IsNotNull(dtCustomers, "dtCustomers is null");
            Assert.IsNotNull(dtCustomers.Rows, "dtCustomers.Rows is null");
            Assert.IsNotNull(dtCustomers.Columns, "dtCustomers.Columns is null");

            int colCount = dtCustomers.Columns.Count;
            int recCount = dtCustomers.Rows.Count;

            Assert.IsTrue(colCount > 0, "dtCustomers # of columns is 0");
            Assert.IsTrue(recCount > 0, "dtCustomers # of rows is 0");
        }

        [TestMethod]
        public void ValidateCustomerStruct()
        {
            DataTable dtCustomers = DataAccess.ExecuteQuery("SELECT * FROM Customers");

            List<CustomerStruct> lstCustomers = dtCustomers.Cast<CustomerStruct>();
            Assert.IsNotNull(lstCustomers, "lstCustomers is null");
            Assert.IsTrue(lstCustomers.Count == dtCustomers.Rows.Count, "lstCustomers records don't match dtCustomers");

            for (int i = 0; i < lstCustomers.Count; i++)
                Assert.IsTrue(lstCustomers[i].Equals(dtCustomers.Rows[i]), "Customer record # " + i + " does not match.");
        }

        [TestMethod]
        public void ValidateCustomerClass()
        {
            DataTable dtCustomers = DataAccess.ExecuteQuery("SELECT * FROM Customers");

            List<CustomerClass> lstCustomers = dtCustomers.Cast<CustomerClass>();
            Assert.IsNotNull(lstCustomers, "lstCustomers is null");
            Assert.IsTrue(lstCustomers.Count == dtCustomers.Rows.Count, "lstCustomers records don't match dtCustomers");

            for (int i = 0; i < lstCustomers.Count; i++)
                Assert.IsTrue(lstCustomers[i].Equals(dtCustomers.Rows[i]), "Customer record # " + i + " does not match.");
        }

        [TestMethod]
        public void ValidateStoredProcedureDataTable()
        {
            using (DataAccess daConn = DataAccess.GetDataAccess(null))
            {
                DataTable dtOutput;

                DataAccessParam[] arrParams = new DataAccessParam[1];
                arrParams[0] = DataAccess.GetParameter("@CustomerID", ParamType.String, 5, "QUICK");
                ReturnCode retCode = daConn.ExecuteStoredProcedure("[CustOrderHist]", arrParams, out dtOutput);

                Assert.IsNotNull(dtOutput, "dtOutput is null");
                Assert.IsTrue(dtOutput.Columns.Count == 2, "dtOutput does not have 2 columns");
                Assert.IsTrue(dtOutput.Rows.Count > 0, "dtOutput has 0 rows");

            }
        }

        [TestMethod]
        public void ValidateStoredProcedureDataSet()
        {
            using (DataAccess daConn = DataAccess.GetDataAccess(null))
            {
                DataSet dsOutput;

                DataAccessParam[] arrParams = new DataAccessParam[1];
                arrParams[0] = DataAccess.GetParameter("@CustomerID", ParamType.String, 5, "QUICK");
                ReturnCode retCode = daConn.ExecuteStoredProcedure("[CustOrderHist]", arrParams, out dsOutput);

                Assert.IsNotNull(dsOutput, "dsOutput is null");
                Assert.IsNotNull(dsOutput.Tables, "dsOutput.Tables is null");

                Assert.IsTrue(dsOutput.Tables.Count == 1, "dsOutput # of tables is not 1");
                Assert.IsTrue(dsOutput.Tables[0].Columns.Count == 2, "dsOutput's first table does not have 2 columns");
                Assert.IsTrue(dsOutput.Tables[0].Rows.Count > 0, "dsOutput's first table has 0 rows");

            }
        }

        [TestMethod]
        public void ValidateStoredProcedureDataReader()
        {
            using (DataAccess daConn = DataAccess.GetDataAccess(null))
            {
                DbDataReader drOutput;

                DataAccessParam[] arrParams = new DataAccessParam[1];
                arrParams[0] = DataAccess.GetParameter("@CustomerID", ParamType.String, 5, "QUICK");
                ReturnCode retCode = daConn.ExecuteStoredProcedure("[CustOrderHist]", arrParams, out drOutput);

                Assert.IsNotNull(drOutput, "drOutput is null");

                List<CustomerOrderStruct> lstCustOrdStruct = new List<CustomerOrderStruct>();
                List<CustomerOrderClass> lstCustOrdClass = new List<CustomerOrderClass>();

                while (drOutput.Read())
                {
                    lstCustOrdStruct.Add(drOutput.ToType<CustomerOrderStruct>());
                    lstCustOrdClass.Add(drOutput.ToType<CustomerOrderClass>());
                }

                Assert.IsNotNull(lstCustOrdStruct, "lstCustOrdStruct is null");
                Assert.IsNotNull(lstCustOrdClass, "lstCustOrdClass is null");

                for (int i = 0; i < lstCustOrdClass.Count; i++)
                {
                    Assert.IsTrue(
                        lstCustOrdClass[i].ProductName == lstCustOrdStruct[i].ProductName && 
                        lstCustOrdClass[i].Quantity == lstCustOrdStruct[i].Quantity, 
                        "CustomerOrder record # " + i + " does not match."
                    );
                }
            }
        }

        #region CustomerStruct Definition

        protected struct CustomerStruct
        {
            [Bind("CustomerID")]
            public string CustomerID;
            [Bind("CompanyName")]
            public string CompanyName;
            [Bind("ContactName")]
            public string ContactName;
            [Bind("ContactTitle")]
            public string ContactTitle;
            [Bind("Address")]
            public string Address;
            [Bind("City")]
            public string City;
            [Bind("Region")]
            public string Region;
            [Bind("PostalCode")]
            public string PostalCode;
            [Bind("Country")]
            public string Country;
            [Bind("Phone")]
            public string Phone;
            [Bind("Fax")]
            public string Fax;

            public bool Equals(DataRow drCustomer)
            {
                return DBUtility.GetString(drCustomer["CustomerID"]).Equals(CustomerID);
            }
        }

        #endregion

        #region CustomerClass Definition

        protected class CustomerClass
        {
            [Bind("CustomerID")]
            public string CustomerID;
            [Bind("CompanyName")]
            public string CompanyName;
            [Bind("ContactName")]
            public string ContactName;
            [Bind("ContactTitle")]
            public string ContactTitle;
            [Bind("Address")]
            public string Address;
            [Bind("City")]
            public string City;
            [Bind("Region")]
            public string Region;
            [Bind("PostalCode")]
            public string PostalCode;
            [Bind("Country")]
            public string Country;
            [Bind("Phone")]
            public string Phone;
            [Bind("Fax")]
            public string Fax;

            public bool Equals(DataRow drCustomer)
            {
                return DBUtility.GetString(drCustomer["CustomerID"]).Equals(CustomerID);
            }
        }

        #endregion

        #region CustomerOrderStruct Definition

        protected struct CustomerOrderStruct
        {
            [Bind("ProductName")]
            public string ProductName;
            [Bind("Total")]
            public int Quantity;

            public bool Equals(DataRow drCustomer)
            {
                return 
                    DBUtility.GetString(drCustomer["ProductName"]).Equals(ProductName) &&
                    DBUtility.GetInteger(drCustomer["Total"]).Equals(Quantity);
            }
        }

        #endregion

        #region CustomerOrderClass Definition

        protected class CustomerOrderClass
        {
            [Bind("ProductName")]
            public string ProductName;
            [Bind("Total")]
            public int Quantity;

            public bool Equals(DataRow drCustomer)
            {
                return
                    DBUtility.GetString(drCustomer["ProductName"]).Equals(ProductName) &&
                    DBUtility.GetInteger(drCustomer["Total"]).Equals(Quantity);
            }
        }

        #endregion

    }
}
